//! Zig implementation of Asterinas memory management
//! SPDX-License-Identifier: MPL-2.0

const std = @import("std");
const builtin = @import("builtin");

// Core types matching Rust implementation
pub const Vaddr = usize;
pub const Paddr = usize;
pub const Daddr = u64;
pub const PagingLevel = u8;

// Architecture constants (matching x86_64)
pub const PAGE_SIZE: usize = 4096;
pub const BASE_PAGE_SIZE: usize = PAGE_SIZE;
pub const NR_LEVELS: PagingLevel = 4;
pub const HIGHEST_TRANSLATION_LEVEL: PagingLevel = 4;
pub const PTE_SIZE: usize = 8;
pub const ADDRESS_WIDTH: usize = 48;
pub const VA_SIGN_EXT: bool = true;

// Memory layout constants
pub const MAX_USERSPACE_VADDR: Vaddr = 0x0000_8000_0000_0000 - PAGE_SIZE;
pub const KERNEL_VADDR_START: Vaddr = 0xffff_8000_0000_0000;
pub const KERNEL_VADDR_END: Vaddr = 0xffff_ffff_ffff_0000;

// Re-export modules
pub const frame = @import("frame.zig");
pub const heap = @import("heap.zig");
pub const page_table = @import("page_table.zig");
pub const vm_space = @import("vm_space.zig");
pub const dma = @import("dma.zig");

// Core utility functions
pub inline fn isPageAligned(addr: usize) bool {
    return (addr & (PAGE_SIZE - 1)) == 0;
}

pub inline fn alignDown(addr: usize, alignment: usize) usize {
    return addr & ~(alignment - 1);
}

pub inline fn alignUp(addr: usize, alignment: usize) usize {
    return alignDown(addr + alignment - 1, alignment);
}

pub inline fn pageSize(level: PagingLevel) usize {
    const sub_pages = BASE_PAGE_SIZE / PTE_SIZE;
    return BASE_PAGE_SIZE << (@as(usize, @intCast(std.math.log2(sub_pages))) * (@as(usize, level) - 1));
}

pub inline fn paddrToVaddr(paddr: Paddr) Vaddr {
    // 简化的物理地址到虚拟地址转换
    // 在实际实现中，这需要根据具体的内存映射来实现
    return paddr + KERNEL_VADDR_START;
}

pub inline fn vaddrToPaddr(vaddr: Vaddr) Paddr {
    // 简化的虚拟地址到物理地址转换
    if (vaddr >= KERNEL_VADDR_START) {
        return vaddr - KERNEL_VADDR_START;
    }
    return 0; // 用户空间地址需要通过页表转换
}

// Error types
pub const MemoryError = error{
    OutOfMemory,
    InvalidAddress,
    InvalidAlignment,
    InvalidSize,
    PermissionDenied,
    AlreadyMapped,
    NotMapped,
};

// Page properties and flags
pub const PageFlags = packed struct {
    present: bool = false,
    writable: bool = false,
    user_accessible: bool = false,
    write_through: bool = false,
    cache_disabled: bool = false,
    accessed: bool = false,
    dirty: bool = false,
    huge_page: bool = false,
    global: bool = false,
    no_execute: bool = false,
    _reserved: u22 = 0,

    pub const NONE = PageFlags{};
    pub const READ_ONLY = PageFlags{ .present = true };
    pub const READ_WRITE = PageFlags{ .present = true, .writable = true };
    pub const USER_READ_ONLY = PageFlags{ .present = true, .user_accessible = true };
    pub const USER_READ_WRITE = PageFlags{ .present = true, .writable = true, .user_accessible = true };
};

pub const CachePolicy = enum {
    Cached,
    Uncached,
    WriteCombining,
    WriteThrough,
};

pub const PageProperty = struct {
    flags: PageFlags,
    cache_policy: CachePolicy,
};

// Tests
test "basic constants" {
    const testing = std.testing;
    try testing.expect(PAGE_SIZE == 4096);
    try testing.expect(isPageAligned(0x1000));
    try testing.expect(!isPageAligned(0x1001));
}

test "address alignment" {
    const testing = std.testing;
    try testing.expectEqual(@as(usize, 0x1000), alignDown(0x1234, PAGE_SIZE));
    try testing.expectEqual(@as(usize, 0x2000), alignUp(0x1234, PAGE_SIZE));
}

test "page size calculation" {
    const testing = std.testing;
    try testing.expectEqual(@as(usize, PAGE_SIZE), pageSize(1));
    try testing.expectEqual(@as(usize, PAGE_SIZE * 512), pageSize(2));
}